#include "Player.h"
#include <random>
#include "SFML\Window\Keyboard.hpp"
#include "SFML\Window\Joystick.hpp"
#include "Isle.h"
#include "OneWayPlatform.h"
#include "Turtoze.h"
#include "Objects/Particle.h"
#include "FadeToBlack.h"
#include "Fire.h"


#include <iostream>
using namespace std;

Player::Player(GameState *gameState) : PhysicalObject(gameState)
{
	addProperty("Player");
	setLayer(1);

	getBodyDef()->type = b2_dynamicBody;
	getBodyDef()->fixedRotation = true;
	b2FixtureDef *fixDef = new b2FixtureDef;
	b2PolygonShape *shape = new b2PolygonShape;
	shape->SetAsBox(0.75f, 0.75f);
	fixDef->shape = shape;
	fixDef->density = 2.0f;
	fixDef->restitution = 0.0f;
	fixDef->friction = 1.0f;
	addFixtureDef(fixDef);
	setRotation(0.0f);

	m_onFloor = false;
	m_previousOnFloor = false;
	m_jumpPressed = false;
	m_canStepDown = false;
	m_onAirTimer = 0.0f;
	m_jumpState = 0;
	m_shootingSpeed = 6.0f;
	m_shootingCooldown = 0.0f;
	m_shootingAngle = 0.0f;

	setColor(1.0f, 1.0f, 1.0f);
	setSize(b2Vec2(4.0f, 4.0f));

	m_shader = gameState->getShaderManager().getShader("player");
	setColor(1.0f, 0.5f, 0.1f);

	m_time = 0;
	m_particleTimer = 0;
	m_horizontalTimer = 0;
	m_horizontalMaxTimer = 0.25f;
	m_direction = 0;

	m_inAura = false;
	m_killed = false;

	m_fire = NULL;
}


Player::~Player()
{
}

void Player::firstUpdate(){
	for(int i = -2; i < 3; i++){
		for(int j = -1; j < 3; j++){
			b2Vec2 particlePos = b2Vec2(getPosition().x+i*0.1f, getPosition().y+j);
			b2Vec2 posSum = b2Vec2((((rand()%10)/10.0f)-0.5f)*0.5f, (((rand()%10)/10.0f)-0.5f)*0.5f);
			posSum *= 4.0f;
			particlePos += posSum;
				
			Particle *particle = m_gameState->getCurrentScreen()->createParticle();
			particle->setShader(m_gameState->getShaderManager().getShader("particle"));
			if(rand()%2){
				particle->setColor(1.0f, 0.4f, 0.15f, 0.6f);
			}else{
				particle->setColor(1.0f, 0.2f, 0.15f, 0.4f);
			}

			particle->setEndColor(0.2f, 0.2f, 0.2f, 0.0f);
			particle->setSize(b2Vec2(6.0f, 10.0f));
			particle->setPosition(particlePos);
			particle->setLifeTime(0.5f+rand()%6/20.0f);
			particle->setVel(b2Vec2((((rand()%10)/10.0f)-0.5f)*4, 8));
			//, rand()%2+2);
		}
	}
}
void Player::update(double dt){
	m_time += dt;
	m_particleTimer += dt;
	bool jumpPress = Keyboard::isKeyPressed(Keyboard::W) || Keyboard::isKeyPressed(Keyboard::Up) || Joystick::isButtonPressed(0,0);
	bool leftPress = Keyboard::isKeyPressed(Keyboard::A) || Keyboard::isKeyPressed(Keyboard::Left) || Joystick::getAxisPosition(0, Joystick::PovY) < -50.0f;
	bool rightPress = Keyboard::isKeyPressed(Keyboard::D) || Keyboard::isKeyPressed(Keyboard::Right) || Joystick::getAxisPosition(0, Joystick::PovY) > 50.0f;
	bool downPress =  Joystick::getAxisPosition(0,Joystick::Axis::Y) > 70.0f || Joystick::getAxisPosition(0, Joystick::PovX) < -50.0f;
	bool directDownPress = Keyboard::isKeyPressed(Keyboard::S) || Keyboard::isKeyPressed(Keyboard::Down);
	
	float xAxisPosition = Joystick::getAxisPosition(0,Joystick::Axis::X);
	float yAxisPosition = Joystick::getAxisPosition(0,Joystick::Axis::Y);

	float xAxisPosition2 = Joystick::getAxisPosition(0,Joystick::Axis::U);
	float yAxisPosition2 = Joystick::getAxisPosition(0,Joystick::Axis::R);

	if(abs(xAxisPosition2) < 15.0f){
		xAxisPosition2 = 0.0f;
	}

	if(abs(yAxisPosition2) < 15.0f){
		yAxisPosition2 = 0.0f;
	}

	yAxisPosition2 *= -1;

	bool shootPress = xAxisPosition2 != 0 || yAxisPosition2 != 0;// Joystick::isButtonPressed(0,2.0f);

	bool restartPress = Keyboard::isKeyPressed(Keyboard::Q) ||Joystick::isButtonPressed(0, 3);


	if(restartPress || m_killed){
		doKill();
	}

	if(leftPress && !rightPress){
		xAxisPosition = -100.0f;
	}else if(rightPress && !leftPress){
		xAxisPosition = 100.0f;
	}

	if(downPress){
		yAxisPosition = 100.0f;
	}

	m_xAxisPosition = xAxisPosition;

	processContacts();

	// Jump down
	if(m_jumpState==0 && ((downPress && jumpPress) || directDownPress) && m_canStepDown){
		m_jumpState=2;
		m_onFloor = false;
			
		setPosition(b2Vec2(getPosition().x, getPosition().y-0.1f));
		b2Filter filter;
		filter.groupIndex = -2;
		m_body->GetFixtureList()->SetFilterData(filter);
	}else if(m_body->GetFixtureList()->GetFilterData().groupIndex==-2){
		b2Filter filter;
		filter.groupIndex = 2;
		m_body->GetFixtureList()->SetFilterData(filter);
	}

	// Jump movement
	b2Vec2 linearVel = m_body->GetLinearVelocity();
	
	double maxOnAirTimer = 0.12f;

	
	switch(m_jumpState){
	case 0: // On the floor
		if(jumpPress && !m_jumpPressed && m_onFloor){
			m_body->SetLinearVelocity(b2Vec2(linearVel.x, 28));
			//setPosition(b2Vec2(getPosition().x, getPosition().y+10*dt));
			m_jumpState = 1;
			m_gameState->getSoundManager().playSound("jump.wav");
		}
		m_onAirTimer = 0.0f;
		break;
	case 1: // On air
		if(m_onFloor && !m_jumpPressed){
			m_jumpState = 0;
		}else if(jumpPress && m_onAirTimer < maxOnAirTimer){
			m_body->SetLinearVelocity( b2Vec2( linearVel.x, 30) );
		}else{
			m_jumpState = 2;
		}
		m_onAirTimer += dt;
		break;
	case 2: // Falling
		if(m_onFloor){
			m_jumpState = 0;
		}
		
		
		m_onAirTimer += dt;
		break;

	}

	

	// Horizontal movement
	linearVel = m_body->GetLinearVelocity();

	
	
	

	if(abs(xAxisPosition) > 30.0f){
		if(xAxisPosition > 0){
			m_direction = 1;
		}else{
			m_direction = -1;
		}

		m_horizontalTimer += dt;
		if(m_horizontalTimer >= m_horizontalMaxTimer){
			m_horizontalTimer = m_horizontalMaxTimer;
		}
	}else{
		m_horizontalTimer -= dt;
		if(m_horizontalTimer <= 0){
			m_horizontalTimer = 0;
		}
	}
	
	float vel = 18;


	m_body->SetLinearVelocity(b2Vec2((float(m_horizontalTimer/m_horizontalMaxTimer))*vel*m_direction,linearVel.y));

	
	m_jumpPressed = false;
	m_previousOnFloor = m_onFloor;


	if(m_body->GetLinearVelocity().LengthSquared()>0){
		m_particleTimer = 0;
		
		b2Vec2 particlePos = b2Vec2(getPosition().x, getPosition().y);
		//particlePos += b2Vec2((((rand()%10)/10.0f)-0.5f)*0.5f, (((rand()%10)/10.0f)-0.5f)*0.5f);
		Particle *particle = m_gameState->getCurrentScreen()->createParticle();
		particle->setShader(m_gameState->getShaderManager().getShader("iceParticle"));
		particle->setColor(1.0f, 0.8f, 0.5f, 0.7f);
		particle->setEndColor(1.0f, 1.0f, 0.5f, 0.2f);
		particle->setSize(b2Vec2(3.5f, 3.5f));
		particle->setPosition(particlePos);
		particle->setLifeTime(0.6f);
		//, 3);
		
	}


}

void Player::processContacts(){
	m_onFloor = false;
	m_canStepDown = false;

	bool set = false;

	for(unsigned int i = 0; i < m_collisions.size(); i++){
		b2Contact *contact = m_collisions[i];
		b2WorldManifold manifold;
		contact->GetWorldManifold(&manifold);

		b2Fixture *myFixture;
		PhysicalObject *me;
		PhysicalObject *other;

		getContactEntities(contact, &me, &other, &myFixture);

		if(other->hasProperty("stepdown")){
			m_canStepDown = true;
			set = true;
		}

		if(other->hasProperty("oneway")){
			if(me->getPosition().y-0.75f >= other->getPosition().y){
				m_onFloor = true;
			}
		}
		if(other->hasProperty("block")){
			if(abs(manifold.normal.y) > 0.7f){
				m_onFloor = true;
				set = true;
			}
		}
		

		
	}
}

void Player::beginContact(b2Contact *contact){
	

	m_collisions.push_back(contact);


}

void Player::endContact(b2Contact *contact){
	/*b2WorldManifold manifold;
	contact->GetWorldManifold(&manifold);

	PhysicalObject *me = (PhysicalObject*)contact->GetFixtureA()->GetBody()->GetUserData();
	PhysicalObject *other = (PhysicalObject*)contact->GetFixtureB()->GetBody()->GetUserData();
	

	if(me != this){ 
		PhysicalObject *temp;
		temp = me;
		me = other;
		other = temp;
	}

	if(other->hasProperty("oneway")){
		m_onFloor = false;
	}

	if(other->hasProperty("ground")){
		m_onFloor = false;
	}

	if(other->hasProperty("stepdown")){
		m_canStepDown = false;
	}*/

	bool found = false;
	for(unsigned int i = 0; i < m_collisions.size(); i++){
		if(m_collisions[i] == contact){
			m_collisions.erase(m_collisions.begin()+i);
			found = true;
			break;
		}
	}
	assert(found==true);

}

void Player::PreSolve(b2Contact* contact, const b2Manifold* oldManifold){
	PhysicalObject *me = (PhysicalObject*)contact->GetFixtureA()->GetBody()->GetUserData();
	PhysicalObject *other = (PhysicalObject*)contact->GetFixtureB()->GetBody()->GetUserData();

	if(me != this){ // objectB is the thing you've contacted
		PhysicalObject *temp;
		temp = me;
		me = other;
		other = temp;
	}

	if(other->hasProperty("oneway")){
		if(me->getPosition().y-0.75f < other->getPosition().y){
			contact->SetEnabled(false);
			m_onFloor = false;
		}
	}else if(other->hasProperty("enemy")){
		if(m_inAura){
			contact->SetEnabled(false);
		}else{
			m_killed = true;
		}

	}

	/*if(other->hasProperty("RotatingIsle")){
		if(abs(m_xAxisPosition) < 15.0f){
			contact->SetFriction(100.0f);
		}else{
			contact->SetFriction(1);
		}
	}*/
}

void Player::draw(){
	b2Vec2 pos = getPosition();

	b2Vec2 vel = m_body->GetLinearVelocity();
	float linVel = (16.0f-vel.Length())/16.0f;
	linVel *= 0.25f;
	linVel+=abs(vel.x)*0.25f;

	float velX = (vel.x)/256.0f;
	float velY = (vel.y)/256.0f;

	sf::Shader::bind(m_shader);

	m_shader->setParameter("time", (float)m_time);
	m_shader->setParameter("inAura", (float)m_inAura);

	glColor4fv(m_color);
	glPushMatrix();
	{
		glTranslatef(pos.x, pos.y, 0); 
		glScalef(getSize().x, getSize().y, 1);
		glBegin(GL_QUADS);
		{
			glTexCoord2f(0.0f, 1.0f); glVertex3f( -0.5f, -0.5f, -0.2f);
			glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.5f, -0.5f, -0.2f);
			glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.5f, 0.5f, -0.2f);
			glTexCoord2f(0.0f, 0.0f); glVertex3f( -0.5f, 0.5f, -0.2f);
		}
		glEnd();
	}
	glPopMatrix();

	sf::Shader::bind(NULL);

	
}

void Player::doKill(){
	for(int i = -2; i < 3; i++){
		for(int j = -1; j < 3; j++){
			b2Vec2 particlePos = b2Vec2(getPosition().x+i*0.1f, getPosition().y+j);
			b2Vec2 posSum = b2Vec2((((rand()%10)/10.0f)-0.5f)*0.5f, (((rand()%10)/10.0f)-0.5f)*0.5f);
			posSum *= 4.0f;
			particlePos += posSum;
				
			Particle *particle = m_gameState->getCurrentScreen()->createParticle();
			particle->setShader(m_gameState->getShaderManager().getShader("particle"));
			if(rand()%2){
				particle->setColor(1.0f, 0.4f, 0.15f, 0.6f);
			}else{
				particle->setColor(1.0f, 0.2f, 0.15f, 0.4f);
			}

			particle->setEndColor(0.2f, 0.2f, 0.2f, 0.0f);
			particle->setSize(b2Vec2(6.0f, 10.0f));
			particle->setPosition(particlePos);
			particle->setLifeTime(0.5f+rand()%6/20.0f);
			particle->setVel(b2Vec2((((rand()%10)/10.0f)-0.5f)*4.0f, 8.0f));
			//, rand()%2+2);
		}
	}

	FadeToBlack *fadeToBlack = new FadeToBlack(m_gameState, 0.5f);
	m_screen->addObject(fadeToBlack);
	kill();
	m_fire->kill();

	//m_gameState->setCurrentScreen(new HomeScreen(m_gameState));
}